package com.jrowny.proxy
{
	import com.jrowny.controls.SpriteElement;
	import com.jrowny.enum.Notes;
	import com.jrowny.utils.StringUtils;
	
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.net.FileFilter;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	
	import mx.collections.ArrayCollection;
	
	import org.puremvc.as3.patterns.proxy.Proxy;
	
	public class FileProxy extends Proxy
	{
		public static const NAME:String = "FileProxy";
		private static const IMG_FILTER:FileFilter = new FileFilter("Images", "*.jpg;*.jpeg;*.gif;*.png;");
		
		//these should be settings
		public static const HEADER:String = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml">\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n<title>Preview Sprite</title>\n<style>\n!STYLES!</style>\n</head>\n<body>\n'
		
		public var html:String;		 //the rendered html
		public var css:String; 		 //the rendered css
		public var imageFile:File;	 //used for the image only
		public var file:File;		 //used for read/write
		public var previewFile:File; //The file used in preview
		private var _minify:Boolean = false//whether or not to minify the CSS
		private var _spriteSelector:String = "sprite"; //the default sprite selector
		
		
		public function FileProxy()
		{
			css="";
			html="";
			super(NAME);
		}
		
		
		/**
		 * Open Images
		 */
		public function loadImage():void{	
			imageFile = new File();
			imageFile.browseForOpen("Find an image",[IMG_FILTER]);
			imageFile.addEventListener(Event.SELECT,onSelectImageFile);
		}	
		private function onSelectImageFile(event:Event):void{
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadedImage);
			var request:URLRequest = new URLRequest(imageFile.url);
			loader.load(request);
		}
		private function onLoadedImage(event:Event):void{
			previewFile = File.createTempFile(); //Create the temp file that will be used
			sendNotification(Notes.IMAGE_LOADED,event.currentTarget.content as Bitmap);
		}
		
		
		/**
		 * Save CSS and HTML
		 */
		public function saveCSS():void{
			file = new File();
			file.browseForSave("Save CSS");
			file.addEventListener(Event.SELECT,onSelectSaveCSS);
		}
		public function saveHTML():void{
			file = new File();
			file.browseForSave("Save HTML");
			file.addEventListener(Event.SELECT,onSelectSaveHTML);
		}
		/**
		 * file save handlers
		 **/
		private function onSelectSaveCSS(event:Event):void{
			file = event.target as File;
			var stream:FileStream = new FileStream();
			if(!file.extension || file.extension.toLowerCase() != "css"){
				file.nativePath +=".css";
			}
			stream.open(file,FileMode.WRITE);
			stream.writeUTFBytes(css);
			stream.close();
		}
		private function onSelectSaveHTML(event:Event):void{
			file = event.target as File;
			var stream:FileStream = new FileStream();
			if(!file.extension || file.extension.toLowerCase() != "html"){
				file.nativePath +=".html";
			}
			stream.open(file,FileMode.WRITE);
			stream.writeUTFBytes(html);
			stream.close();
		}
		/**
		 * Preview the html in an external browser
		 **/
		public function previewInBrowser():void{			
			navigateToURL(new URLRequest(previewFile.nativePath));
		}
		
		
		
		/**
		 * keep em fresh - this code generates the CSS and HTML
		 **/		
		public function generateCode():void{
			
			//the following strings are used for code formatting TODO:Make thesee customizable
			var lb:String = "";
			var padding:String = "";
			var indent:String ="";
			//only if we're not minifying do we add formating spaces
			if(!_minify){
				lb = "\n";
				indent = "  ";
				padding = indent + StringUtils.padLeft(""," ",_spriteSelector.length+2);
			} 
			//first, build the CSS
			if(elements.length){
				css = indent + "." + _spriteSelector + "{";
				css+= "display:block;" + lb;
				css+= padding + "text-indent:-9000em;" + lb;
				css+= padding + "color:transparent;" + lb;
				css+= padding + "background:url('file://"+imageFile.nativePath.split("\\").join("/")+"')  no-repeat;\n" + indent + "}" + lb + lb; //put the slashes in the right way :)
			}else{
				css = ""; //no need for CSS, we have no elements!!
			}
			padding = "";//reset padding
			
			var elm:SpriteElement;
			for each(elm in elements){		
				//padding is provided for code formating, we don't use tabs because not all systems recognize them
				if(!_minify) padding = StringUtils.padLeft(""," ", elm.elmName.length+2); //2 spaces in front, . or # amd{
				css+=indent;
				css+=(elm.isClass?".":"#");	//is it a class?
				css+= elm.elmName;
				css+=(elm.pseudo.length?":"+elm.pseudo:"");	//add the psuedo class?
				css+= "{background-position:" + (elm.x*-1) + "px " + (elm.y*-1) + "px;";
				//check if this has a non-psuedo class and if it matches TODO: Make this work for either width or height indepentently 
				if(elm.pseudo.length && elementProxy.nonPseudoSizeMatch(elm.baseSelector,elm.width,elm.height)){
					css+="}" + lb;	//just close it since the width and height are specified already
				}else{
					css+= lb + indent + padding + "width:" + elm.width + "px;" + lb;
					css+= indent + padding + "height:" + elm.height + "px;}" + lb;
				}
				if(elements.getItemIndex(elm)!=elements.length-1) css+="" + lb;
			}
			//Start on HTML now
			html=HEADER.replace("!STYLES!",css);//put the CSS in the header			
			for each(var map:Array in elmMap){
				elm = map[0] as SpriteElement; //only select the first item in the map
				html+=indent + "<";
				html+=elm.tag;
				if(elm.isClass){
					html+=' class="' + _spriteSelector + ' ' + elm.elmName + '" ';
				}else{
					html+=' class="' + _spriteSelector + '" id="' + elm.elmName + '" ';
				}
				html+=">"+elm.elmName+"</"+elm.tag+">" + lb;
			}
			
			html+='</body></html>';	//close out the file
			var src:Object = new Object();
			src.css = css;
			src.html = html;
			
			//Update the temp file 
			var stream:FileStream = new FileStream();
			stream.open(previewFile,FileMode.WRITE);
			stream.writeUTFBytes(html);
			stream.close();
			
			sendNotification(Notes.CSS_HTML_GENERATED,src);			
		}
		
		/**
		 * Accessors
		 **/
		public function get elementProxy():ElementProxy{
			return ElementProxy(facade.retrieveProxy(ElementProxy.NAME));
		}
		public function get elements():ArrayCollection{
			return elementProxy.elements as ArrayCollection;
		}
		public function get elmMap():Object{
			return elementProxy.elmMap;
		}
		
		public function get minify():Boolean{
			return _minify;
		}
		public function set minify(value:Boolean):void{
			_minify = value;
			//rewrite the code since we minified
			generateCode();
		}
		public function get spriteSelector():String{
			return _spriteSelector;
		}
		public function set spriteSelector(value:String):void{
			_spriteSelector = value;
			//rewrite the code since we minified
			generateCode();
		}
	}
}